﻿//----------------------------------------------------------------------------
// NFC Orchestra
// An NFC demo app for Windows Phone 8+
// Copyright (C) Andreas Jakl and Rina Ahmed
// https://nfcorchestra.codeplex.com/
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Navigation;
using Windows.Networking.Proximity;
using Windows.Phone.Speech.Recognition;
using Microsoft.Phone.Controls;
using NdefLibrary.Ndef;
using NfcOrchestra.Resources;

namespace NfcOrchestra
{
    public partial class SetupPage : PhoneApplicationPage
    {
        private ProximityDevice _device;
        private bool _initialized;
        private readonly byte[] _nfcMusicType = Encoding.UTF8.GetBytes("msday.at:music");
        private SpeechRecognizerUI _recognizer;
        private long _publishingMessageId = 0;

        public SetupPage()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            ThreadPool.QueueUserWorkItem(func => Initialize());
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            _initialized = false;
            if (_device != null && _publishingMessageId != 0)
            {
                _device.StopPublishingMessage(_publishingMessageId);
                _publishingMessageId = 0;
            }
            if (_recognizer != null)
            {
                _recognizer.Dispose();
                _recognizer = null;
            }
        }

        private void Initialize()
        {
            if (_initialized) return;

            try
            {
                _device = ProximityDevice.GetDefault();
                if (_device == null)
                {
                    ShowMessageBox(AppResources.StatusNfcErrorText, AppResources.StatusNfcErrorTitle);
                    return;
                }

                _recognizer = new SpeechRecognizerUI();
            }
            catch (Exception ex)
            {
                ShowMessageBox(String.Format(AppResources.ErrorInitText, ex.Message), AppResources.ErrorInitTitle);
            }

            _initialized = true;
        }

        private void MessageTransmittedHandler(ProximityDevice sender, long messageid)
        {
            _publishingMessageId = 0;
            _device.StopPublishingMessage(messageid);
            ShowMessageBox(AppResources.NfcInstrumentWrittenText, AppResources.NfcInstrumentWrittenTitle);
        }

        private async Task<SpeechRecognitionUIResult> RecognizeSpeech()
        {
            if (!_initialized || _recognizer == null)
            {
                ShowMessageBox(AppResources.StatusNotInitializedTitle, AppResources.StatusNotInitializedText);
                return null;
            }
            try
            {
                return await _recognizer.RecognizeWithUIAsync();
            }
            catch (Exception ex)
            {
                if ((UInt32)ex.HResult == 0x80045508)
                {
                    // A speech operation was aborted by a system call, for example fast app switching or an incoming phone call.
                    ShowMessageBox(AppResources.StatusSpeechInterrupted, AppResources.StatusRecognizerError);
                }
                else if ((UInt32)ex.HResult == 0x800455BC)
                {
                    ShowMessageBox(AppResources.StatusLanguageNotSupported, AppResources.StatusRecognizerError);
                }
                else
                {
                    ShowMessageBox(AppResources.StatusRecognizerError, ex.Message);
                }
            }
            return null;
        }
        

        private void ShowMessageBox(string text, string title)
        {
            Dispatcher.BeginInvoke(() => MessageBox.Show(text, title, MessageBoxButton.OK));
        }

        private void PublishMusicRecord(string payload)
        {
            if (!_initialized || _device == null)
            {
                ShowMessageBox(AppResources.StatusNotInitializedText, AppResources.StatusNotInitializedTitle);
                return;
            }
            if (_publishingMessageId != 0)
            {
                ShowMessageBox(AppResources.StatusAlreadyPublishingText, AppResources.StatusAlreadyPublishingTitle);
                return;
            }
            var record = new NdefRecord
            {
                TypeNameFormat = NdefRecord.TypeNameFormatType.ExternalRtd,
                Type = _nfcMusicType,
                Payload = Encoding.UTF8.GetBytes(payload)
            };
            var msg = new NdefMessage { record };
            _publishingMessageId = _device.PublishBinaryMessage("NDEF:WriteTag", msg.ToByteArray().AsBuffer(),
                MessageTransmittedHandler);
            ShowMessageBox(AppResources.NfcWriteInstrumentText, AppResources.NfcWriteInstrumentTitle);
        }

        private async void BtnVoice_Click(object sender, RoutedEventArgs e)
        {
            if (!_initialized || _recognizer == null || _device == null)
            {
                ShowMessageBox(AppResources.StatusNotInitializedText, AppResources.StatusNotInitializedTitle);
                return;
            }
            var speechResult = await RecognizeSpeech();
            if (speechResult == null || speechResult.ResultStatus != SpeechRecognitionUIStatus.Succeeded) return;

            var speechText = speechResult.RecognitionResult.Text;
            PublishMusicRecord("3" + speechText);
        }

        private void BtnBeat_Click(object sender, RoutedEventArgs e)
        {
            PublishMusicRecord("0");
        }

        private void BtnSax_Click(object sender, RoutedEventArgs e)
        {
            PublishMusicRecord("1");
        }

        private void BtnGuitar_Click(object sender, RoutedEventArgs e)
        {
            PublishMusicRecord("2");
        }
    }
}